package cc.magicjson.example.demo.mmr;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;

public class CosineSimilarityDemo {

    // 计算两个向量之间的余弦相似度
    public static double cosineSimilarity(Map<String, Double> vector1, Map<String, Double> vector2) {
        // 找出两个向量共有的维度
        Set<String> both = new HashSet<>(vector1.keySet());
        both.retainAll(vector2.keySet());

        double scalarProduct = 0.0;  // 用于存储点积
        double norm1 = 0.0;  // 用于存储向量1的范数的平方
        double norm2 = 0.0;  // 用于存储向量2的范数的平方

        // 计算点积
        for (String k : both) scalarProduct += vector1.get(k) * vector2.get(k);

        // 计算向量1的范数的平方
        for (double v : vector1.values()) norm1 += v * v;

        // 计算向量2的范数的平方
        for (double v : vector2.values()) norm2 += v * v;

        // 返回余弦相似度：点积除以范数乘积
        return scalarProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    public static void main(String[] args) {
        // 示例1：文档相似度
        System.out.println("示例1：文档相似度");

        // 创建第一个文档的词频向量
        Map<String, Double> doc1 = new HashMap<>();
        doc1.put("hello", 1.0);  // "hello" 出现1次
        doc1.put("world", 2.0);  // "world" 出现2次
        doc1.put("java", 3.0);   // "java" 出现3次

        // 创建第二个文档的词频向量
        Map<String, Double> doc2 = new HashMap<>();
        doc2.put("hello", 2.0);   // "hello" 出现2次
        doc2.put("world", 3.0);   // "world" 出现3次
        doc2.put("program", 1.0); // "program" 出现1次

        // 计算文档相似度
        double similarity = cosineSimilarity(doc1, doc2);
        System.out.printf("文档相似度: %.4f%n", similarity);

        // 示例2：用户偏好相似度
        System.out.println("\n示例2：用户偏好相似度");

        // 创建第一个用户的电影类型偏好向量
        Map<String, Double> user1 = new HashMap<>();
        user1.put("action", 5.0);  // 动作片评分5分
        user1.put("comedy", 3.0);  // 喜剧片评分3分
        user1.put("drama", 1.0);   // 剧情片评分1分

        // 创建第二个用户的电影类型偏好向量
        Map<String, Double> user2 = new HashMap<>();
        user2.put("action", 4.0);  // 动作片评分4分
        user2.put("comedy", 4.0);  // 喜剧片评分4分
        user2.put("scifi", 2.0);   // 科幻片评分2分

        // 计算用户偏好相似度
        similarity = cosineSimilarity(user1, user2);
        System.out.printf("用户偏好相似度: %.4f%n", similarity);

        // 示例3：向量相似度
        System.out.println("\n示例3：向量相似度");

        // 创建第一个向量
        Map<String, Double> vector1 = new HashMap<>();
        vector1.put("x", 1.0);  // x 分量为 1
        vector1.put("y", 2.0);  // y 分量为 2
        vector1.put("z", 3.0);  // z 分量为 3

        // 创建第二个向量
        Map<String, Double> vector2 = new HashMap<>();
        vector2.put("x", 4.0);  // x 分量为 4
        vector2.put("y", 5.0);  // y 分量为 5
        vector2.put("z", 6.0);  // z 分量为 6

        // 计算向量相似度
        similarity = cosineSimilarity(vector1, vector2);
        System.out.printf("向量相似度: %.4f%n", similarity);
    }
}